package com.lanjiu.lib.business.option;

import com.lanjiu.lib.utils.th.Threader;
import com.lanjiu.pro.file.BigFileFragment;
import com.lanjiu.pro.file.BigFileHead;
import com.lanjiu.pro.file.FileContent;
import com.lanjiu.pro.file.FriendsTransmissionRequest;
import com.lanjiu.pro.file.FriendsTransmissionResponse;
import com.lanjiu.pro.file.GroupTransmissionRequest;
import com.lanjiu.pro.file.GroupTransmissionResponse;
import com.lanjiu.pro.file.OriginalPictureVideoFriendsTransmission;
import com.lanjiu.pro.file.OriginalPictureVideoGroupTransmission;
import com.lanjiu.lib.business.FileContentFactory;
import com.lanjiu.lib.business.FileTransmissionCache;
import com.lanjiu.lib.business.OriginalPictureVideoTransmissionCreator;
import com.lanjiu.lib.business.TransmissionConstant;
import com.lanjiu.lib.business.handler.FileReceiverHandler;
import com.lanjiu.lib.business.listener.OnTransmissionFinishListener;
import com.lanjiu.lib.business.util.FileJCRC32;
import com.lanjiu.lib.business.util.FilePackageCheckSumResult;
import com.lanjiu.lib.utils.log.Logger;
import com.lanjiu.lib.utils.sp.SharedPreferenceHelper;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @description: 文件传输(接收者)
 * @author: Panwei
 * @date: 2019/10/31 9:35
 */
public class FileTransmissionReceiver {

    private FileJCRC32 mJCRC32;
    private SharedPreferenceHelper mSPHelper;
    private FileReceiverHandler mFileReceiverHandler;
    private ByteBuffer mByteBuffer;
    private OnTransmissionFinishListener mTransmissionFinishListener;

    private OriginalPictureVideoFriendsTransmission mFriendTransmission;
    private OriginalPictureVideoGroupTransmission mGroupTransmission;

    private FileTransmissionChannel mFileTransmissionChannel;

    private boolean isApk;

    public FileTransmissionReceiver(SharedPreferenceHelper spHelper, FileReceiverHandler fileReceiverHandler) {
        this.mJCRC32 = new FileJCRC32();
        this.mSPHelper = spHelper;
        this.mFileReceiverHandler = fileReceiverHandler;
        this.mFileTransmissionChannel = FileTransmissionChannel.get();
    }

    public void setOnTransmissionFinishListener(OnTransmissionFinishListener listener) {
        this.mTransmissionFinishListener = listener;
    }

    // 个人下载
    public void transmissionFilePersonReceive(FileTransmissionCache cache, FileContent requestFileContent, OriginalPictureVideoFriendsTransmission friend) {
        isApk = cache.getClientPath().endsWith(".apk");
        mFriendTransmission = friend;
        FileContent responseFileContent = verifyPersonTransmissionResponse(requestFileContent);
        if (responseFileContent == null) {
            if (mTransmissionFinishListener != null)
                mTransmissionFinishListener.onTransmissionFinish(cache.getServerPath());
            return;
        }
        if (TransmissionConstant.FILE_HEAD.equals(responseFileContent.getPackageKind())) {
            // 新的下载
            transmissionFileHeadReceive(cache, responseFileContent, false);
        } else if (TransmissionConstant.FILE_FRAGMENT.equals(responseFileContent.getPackageKind())) {
            // 断点下载
            transmissionFileFragmentReceive(cache, responseFileContent, false);
        } else {
            if (mFileReceiverHandler != null)
                mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_UNKNOWN_KIND, "无效操作");

            if (mTransmissionFinishListener != null)
                mTransmissionFinishListener.onTransmissionFinish(cache.getServerPath());
        }
    }

    // 群组下载
    public void transmissionFileGroupReceive(FileTransmissionCache cache, FileContent requestFileContent, OriginalPictureVideoGroupTransmission group) {
        isApk = cache.getClientPath().endsWith(".apk");
        mGroupTransmission = group;
        FileContent responseFileContent = verifyGroupTransmissionResponse(requestFileContent);
        if (responseFileContent == null) {
            if (mTransmissionFinishListener != null)
                mTransmissionFinishListener.onTransmissionFinish(cache.getServerPath());
            return;
        }
        if (TransmissionConstant.FILE_HEAD.equals(responseFileContent.getPackageKind())) {
            // 新的下载
            transmissionFileHeadReceive(cache, responseFileContent, true);
        } else if (TransmissionConstant.FILE_FRAGMENT.equals(responseFileContent.getPackageKind())) {
            // 断点下载
            transmissionFileFragmentReceive(cache, responseFileContent, true);
        } else {
            if (mFileReceiverHandler != null)
                mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_UNKNOWN_KIND, "无效操作");

            if (mTransmissionFinishListener != null)
                mTransmissionFinishListener.onTransmissionFinish(cache.getServerPath());
        }
    }

    // 校验(个人) 3次机会
    private FileContent verifyPersonTransmissionResponse(FileContent requestFileContent) {
        int mVerifyFailCount = 0;
        int mReconnectCount = 0;
        FriendsTransmissionRequest request;
        FriendsTransmissionResponse response;
        FilePackageCheckSumResult checkSumResult;
        do {
            if (mVerifyFailCount >= TransmissionConstant.DEFAULT_VERIFY_FAIL_COUNT) {
                if (mFileReceiverHandler != null)
                    mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_VERIFY_FAIL, "多次校验失败");

                return null;
            }
            if (mFriendTransmission == null) {
                if (mFileReceiverHandler != null)
                    mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_ENTITY_NULL, "传入实体为空");
                return null;
            }
            try {
                request = mJCRC32.packageCheckSumRequest(OriginalPictureVideoTransmissionCreator.merge(mFriendTransmission, requestFileContent));
                response = mFileTransmissionChannel.service().originalFriendsTransmissionDownload(request);
                checkSumResult = mJCRC32.checkSumValidateFriendsResponse(response);
                if (checkSumResult.b_result) {
                    break;
                } else {
                    mVerifyFailCount++;
                    Logger.print("文件校验失败，重新获取");
                }
            } catch (Exception e) {
                if (e.getMessage().contains("UNAVAILABLE")) {
                    mFileTransmissionChannel.reconnect();
                    Threader.sleep(500);
                    mReconnectCount++;
                    if (mReconnectCount >= 3) {
                        if (mFileReceiverHandler != null)
                            mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_CONNECT_ERROR, "连接异常");
                        Logger.print("Error", e.getMessage());
                        return null;
                    }
                } else {
                    if (mFileReceiverHandler != null)
                        mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_FAIL, "服务器异常");
                    Logger.print("Error", e.getMessage());
                    return null;
                }
            }
        } while (true);
        if (TransmissionConstant.FILE_NON_EXISTENT.equalsIgnoreCase(response.getFriendsPictureVideoMessage().getFileContent().getPackageKind())) {
            if (mFileReceiverHandler != null)
                mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_FILE_NOT_EXISTS, "服务器文件不存在");
            Logger.print("Error", "服务器文件不存在");
            return null;
        }
        return response.getFriendsPictureVideoMessage().getFileContent();
    }

    // 校验(群组) 3次机会
    private FileContent verifyGroupTransmissionResponse(FileContent requestFileContent) {
        int mVerifyFailCount = 0;
        int mReconnectCount = 0;
        GroupTransmissionRequest request;
        GroupTransmissionResponse response;
        FilePackageCheckSumResult checkSumResult;
        do {
            if (mVerifyFailCount >= TransmissionConstant.DEFAULT_VERIFY_FAIL_COUNT) {
                if (mFileReceiverHandler != null)
                    mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_VERIFY_FAIL, "多次校验失败");

                return null;
            }
            if (mGroupTransmission == null) {
                if (mFileReceiverHandler != null)
                    mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_ENTITY_NULL, "传入实体为空");
                return null;
            }

            try {
                request = mJCRC32.packageCheckSumGroupRequest(OriginalPictureVideoTransmissionCreator.merge(mGroupTransmission, requestFileContent));
                response = mFileTransmissionChannel.service().originalGroupTransmissionDownload(request);
                checkSumResult = mJCRC32.checkSumValidateGroupResponse(response);
                if (checkSumResult.b_result) {
                    break;
                } else {
                    mVerifyFailCount++;
                    Logger.print("文件校验失败，重新获取");
                }
            } catch (Exception e) {
                if (e.getMessage().contains("UNAVAILABLE")) {
                    mFileTransmissionChannel.reconnect();
                    Threader.sleep(500);
                    mReconnectCount++;
                    if (mReconnectCount >= 3) {
                        if (mFileReceiverHandler != null)
                            mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_CONNECT_ERROR, "连接异常");
                        Logger.print("Error", e.getMessage());
                        return null;
                    }
                } else {
                    if (mFileReceiverHandler != null)
                        mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_FAIL, "服务器异常");
                    Logger.print("Error", e.getMessage());
                    return null;
                }
            }
        } while (true);
        if (TransmissionConstant.FILE_NON_EXISTENT.equalsIgnoreCase(response.getGroupPictureVideoMessage().getFileContent().getPackageKind())) {
            if (mFileReceiverHandler != null)
                mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_FILE_NOT_EXISTS, "服务器文件不存在");
            Logger.print("Error", "服务器文件不存在");
            return null;
        }
        return response.getGroupPictureVideoMessage().getFileContent();
    }


    // 接收文件头(新的下载)
    private void transmissionFileHeadReceive(FileTransmissionCache cache, FileContent responseFileContentHead, boolean isGroup) {
        BigFileHead fileHead = responseFileContentHead.getBigFileHead();
        Logger.print("发送大文件请求，文件大小[" + fileHead.getLength() + "b]碎片数量[" + fileHead.getCount() + "]");
        cache.setPackageCount(fileHead.getCount());
        cache.setTotalLength(fileHead.getLength());
        cache.setTransmissionCount(0);
        cache.setTransmissionPosition(0);
        cache.setTransmissionLength(0);
        if (mFileReceiverHandler != null)
            mFileReceiverHandler.sendStartMessage();
        FileContent responseFileContentFragment;
        if (isGroup)
            responseFileContentFragment = verifyGroupTransmissionResponse(FileContentFactory.createDownloadFileContentByPosition(cache.getServerPath(), 0));
        else
            responseFileContentFragment = verifyPersonTransmissionResponse(FileContentFactory.createDownloadFileContentByPosition(cache.getServerPath(), 0));
        transmissionFileFragmentReceive(cache, responseFileContentFragment, isGroup);
    }

    // 接收文件包(断点下载)
    private void transmissionFileFragmentReceive(FileTransmissionCache cache, FileContent responseFileContent, boolean isGroup) {
        if (responseFileContent == null) {
            if (mTransmissionFinishListener != null)
                mTransmissionFinishListener.onTransmissionFinish(cache.getServerPath());
            return;
        }
        int mIOExceptionCount = 0;
        int mFragmentTransmissionError = 0;
        while (TransmissionConstant.FILE_FRAGMENT.equals(responseFileContent.getPackageKind())) {
            BigFileFragment fileFragment = responseFileContent.getBigFileFragment();
            long position = fileFragment.getPosition();
            long size = fileFragment.getLength();
            int count = cache.getTransmissionCount();
            long transmissionLength;
            try {
                RandomAccessFile write = new RandomAccessFile(cache.getClientPath(), "rw");
                if (size == fileFragment.getData().size()) {
                    mFragmentTransmissionError = 0;
                    FileChannel writeChannel = write.getChannel();
                    clearByteBuffer();
                    mByteBuffer = writeChannel.map(FileChannel.MapMode.READ_WRITE, position, size);
                    mByteBuffer.put(fileFragment.getData().asReadOnlyByteBuffer());
                    transmissionLength = write.length();
                    writeChannel.close();
                    writeChannel = null;
                    write.close();
                    write = null;

                    position = position + size;
                    cache.setTransmissionPosition(position);
                    cache.setTransmissionCount(++count);
                    if (size != 0) cache.setTransmissionLength(transmissionLength);
                    Logger.print("收到文件包[" + cache.getTransmissionLength() + "]");
                    if (!isApk) mSPHelper.setObject(cache.getClientPath(), cache);
                    mIOExceptionCount = 0;
                } else {
                    transmissionLength = write.length();
                    mFragmentTransmissionError++;
                }
                if (mFragmentTransmissionError > 6) {
                    if (mFileReceiverHandler != null)
                        mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_IO_EXCEPTION, "数据包多次不匹配");


                    if (mTransmissionFinishListener != null)
                        mTransmissionFinishListener.onTransmissionFinish(cache.getServerPath());
                    return;
                }
            } catch (IOException e) {
                mIOExceptionCount++;
                if (mIOExceptionCount > TransmissionConstant.DEFAULT_IO_EXCEPTION_COUNT) {
                    if (mFileReceiverHandler != null)
                        mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_IO_EXCEPTION, "多次IO异常");


                    if (mTransmissionFinishListener != null)
                        mTransmissionFinishListener.onTransmissionFinish(cache.getServerPath());
                    return;
                }
                Logger.print("Error", e.getMessage());
                transmissionLength = cache.getTransmissionLength();
            }
            if (mFileReceiverHandler != null)
                mFileReceiverHandler.sendProgressMessage((int) (transmissionLength * 1f / cache.getTotalLength() * 100));
            if (cache.getPackageCount() <= count && cache.getTotalLength() == transmissionLength) {
                if (isGroup)
                    responseFileContent = verifyGroupTransmissionResponse(FileContentFactory.createDownloadFileContentFoot(cache.getServerPath(), true));
                else
                    responseFileContent = verifyPersonTransmissionResponse(FileContentFactory.createDownloadFileContentFoot(cache.getServerPath(), true));
            } else {
                if (isGroup)
                    responseFileContent = verifyGroupTransmissionResponse(FileContentFactory.createDownloadFileContentByPosition(cache.getServerPath(), position));
                else
                    responseFileContent = verifyPersonTransmissionResponse(FileContentFactory.createDownloadFileContentByPosition(cache.getServerPath(), position));
            }
            if (responseFileContent == null) break;
        }
        transmissionFileFootReceive(cache, responseFileContent);
    }

    // 接收文件尾
    private void transmissionFileFootReceive(FileTransmissionCache cache, FileContent responseFileContentFoot) {
        if (responseFileContentFoot != null && TransmissionConstant.FILE_FOOT.equals(responseFileContentFoot.getPackageKind())) {
            boolean isSuccess = responseFileContentFoot.getBigFileFoot().getIsSuccess();

            Logger.print(isSuccess ? "文件下载成功" : "文件下载失败");
            mSPHelper.delete(cache.getClientPath());
            if (mFileReceiverHandler != null) {
                if (isSuccess)
                    mFileReceiverHandler.sendCompleteMessage(cache.getClientPath());
                else
                    mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_FAIL, "下载失败");
            }
        } else {
            if (mFileReceiverHandler != null)
                mFileReceiverHandler.sendErrorMessage(TransmissionConstant.TRANSMISSION_UNKNOWN_KIND, "无效操作");

        }
        if (mTransmissionFinishListener != null)
            mTransmissionFinishListener.onTransmissionFinish(cache.getServerPath());
    }

    private void clearByteBuffer() {
        if (mByteBuffer != null) {
            mByteBuffer.clear();
            mByteBuffer = null;
        }
    }
}
